package at.ac.tuwien.lsds.schedule;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;

import at.ac.tuwien.lsds.csv.Reader;
import at.ac.tuwien.lsds.csv.ReaderImpl;
import at.ac.tuwien.lsds.csv.Writer;
import at.ac.tuwien.lsds.csv.WriterImpl;
import at.ac.tuwien.lsds.exception.SchedulerException;
import at.ac.tuwien.lsds.model.Application;
import at.ac.tuwien.lsds.schedule.strategy.ScheduleStrategy;
import at.ac.tuwien.lsds.util.ProcessSummaryOutputFile;
import at.ac.tuwien.lsds.util.ProcessSummaryOutputRow;
import at.ac.tuwien.lsds.util.ScheduleStrategyFactory;
import at.ac.tuwien.lsds.util.SchedulerOutputFile;
import at.ac.tuwien.lsds.util.Settings;

public class SchedulerImpl implements Scheduler{
	private static final Logger log = Logger.getLogger(SchedulerImpl.class);
	
	ScheduleStrategy strategy = null;
	Reader reader = null;
	Writer writer = null;
	
	public SchedulerImpl() {
		reader = new ReaderImpl();
		writer = new WriterImpl();
		
		strategy = ScheduleStrategyFactory.createStrategy(Settings.getScheduler());
	}

	@Override
	public ScheduleStrategy getScheduleStrategy() {
		return strategy;
	}

	@Override
	public void setScheduleStrategy(ScheduleStrategy strategy) {
		this.strategy = strategy;
	}


	@Override
	public void schedule() throws SchedulerException{
		if(null == strategy){
			throw new SchedulerException("No scheduling strategy was set. Please do it first.");
		}
		
		List<Application> apps = null;
		
		try {
			apps = reader.readInputData();
		} catch (NumberFormatException e) {
			log.error(e.getMessage());
			throw new SchedulerException(e.getMessage());
		} catch (FileNotFoundException e) {
			log.error(e.getMessage());
			throw new SchedulerException(e.getMessage());
		} catch (IOException e) {
			log.error(e.getMessage());
			throw new SchedulerException(e.getMessage());
		}
		
		if(null == apps){
			throw new SchedulerException("No input data.");
		}
		
		Iterator<Application> iterator = apps.iterator();
		Integer timestamp = 0;
		
		while(iterator.hasNext()){
			Application app = iterator.next();
			
			while(true){
				if(timestamp.equals(app.getTimestamp())){
					strategy.runApplication(app);
					break;
				} else{
					
					
					try {
						Thread.sleep(1);					  
						
					} catch (InterruptedException e) {
						log.error(e.getMessage());
					}
					
					strategy.increaseRunningTime();
					
					SchedulerOutputFile.getInstance().addRow(strategy.getCurrentConsumptionOutputRow(timestamp));
					
					timestamp++;
					
				}
			}
		}
		
		while(strategy.getRunningPMCount()>0){
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				log.error(e.getMessage());
			}
			
			strategy.increaseRunningTime();	
			
			SchedulerOutputFile.getInstance().addRow(strategy.getCurrentConsumptionOutputRow(timestamp));
			
			timestamp++;
		}
		
		log.debug("----- all applications scheduled -----");
		
//		while(0 < strategy.getRunningPMCount()){
//			try {
//				Thread.sleep(100);
//				
//				timestamp += 100;
//			} catch (InterruptedException e) {
//				log.error(e.getMessage());
//			}
//		}
		
		log.debug("----- finish -----");
		
		try {
			writer.writeToCSV(SchedulerOutputFile.getInstance());
		} catch (IOException e) {
			log.error(e.getMessage());
		}
		
		ProcessSummaryOutputFile ps = new ProcessSummaryOutputFile();
		ProcessSummaryOutputRow pr = strategy.getProcessSummaryOutputRow();
		pr.setTotalDuration(timestamp);
		ps.addRow(pr);
		
		try {
			writer.writeToCSV(ps);
		} catch (IOException e) {
			log.error(e.getMessage());
		}
		
	}

}
